﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Novel.Server.Models;
using Novel.Server.Response;
using Novel.Server.Utils;

namespace Novel.Server.Controllers
{
    /// <summary>
    /// 负责显示图片
    /// </summary>
    [Route("api/novel")]
    [ApiController]
    public class NovelController : ControllerBase
    {
        private readonly NovelContext dbContext;
        private readonly IConfiguration conf;

        public NovelController(NovelContext context, IConfiguration configuration)
        {
            dbContext = context;
            conf = configuration;
        }

        /// <summary>
        /// 创建一部小说，返回 GetNovelById 的结果
        /// </summary>
        [HttpPost("create")]
        [Authorize]
        public async Task<IActionResult> CreateNovel([FromBody] NovelCreateDto dto)
        {
            var username = User.Identity.Name;
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username);
            if (user == null || user.IsDeleted)
                return BadRequest(ApiResponse.ErrorResponse("用户不存在", 400));

            var novel = new Models.Novel
            {
                Title = dto.Title,
                AuthorId = user.UserId,
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now,
                IsDeleted = false
            };

            dbContext.Novels.Add(novel);
            await dbContext.SaveChangesAsync();

            var introChapter = new Chapter
            {
                NovelId = novel.NovelId,
                Index = 0,
                Title = "",
                Content = dto.Description,
                IsDeleted = false,
                Visibility = true
            };

            dbContext.Chapters.Add(introChapter);
            await dbContext.SaveChangesAsync();

            return await GetNovelById(novel.NovelId);
        }

        /// <summary>
        /// 获取小说信息
        /// </summary>
        /// <param name="id"></param>
        /// <example>1</example>
        [HttpGet("{id}")]
        public async Task<IActionResult> GetNovelById(int id)
        {
            var novel = await dbContext.Novels
                .Include(n => n.Author)
                .FirstOrDefaultAsync(n => n.NovelId == id && !n.IsDeleted);

            var isAuthor = novel?.Author.Username == User.Identity?.Name;

            if (novel == null || novel.IsDeleted && !isAuthor)
                return NotFound(ApiResponse.ErrorResponse("小说不存在", 404));

            var chapters = await dbContext.Chapters
                .Where(c => c.NovelId == id && !c.IsDeleted && (isAuthor || c.Visibility))
                .OrderBy(c => c.Index)
                .ToListAsync();

            var intro = chapters.FirstOrDefault(c => c.Index == 0);
            var chapterList = chapters
                .Select(c => new
                {
                    id = c.ChapterId,
                    title = c.Title,
                    visibility = c.Visibility,
                    updated_at = c.UpdatedAt
                });
            var tags = await dbContext.Tags
                .Where(t => t.NovelId == id)
                .Select(t => t.TagName)
                .ToListAsync();

            var username = User.Identity.Name;
            var user = username != null ? await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username && !u.IsDeleted) : null;
            var is_favorite = user != null && await dbContext.Favorites.AnyAsync(f => f.UserId == user.UserId && f.NovelId == id);

            var author = new
            {
                id = novel.Author.UserId,
                name = novel.Author.Username,
                avatar = novel.Author.Avatar,
                role = novel.Author.Role,
            };

            return Ok(ApiResponse.SuccessResponse(new
            {
                id = novel.NovelId,
                title = novel.Title,
                author = author,
                cover = novel.Cover,
                created_at = novel.CreatedAt,
                updated_at = novel.UpdatedAt,
                description = intro?.Content,
                tags = tags,
                chapters = chapterList,
                is_favorite = is_favorite,
            }));
        }

        /// <summary>
        /// 获取小说章节信息
        /// </summary>
        [HttpGet("{nid}/chapter/{cid}")]
        public async Task<IActionResult> GetChapterById(int nid, int cid)
        {
            var username = User.Identity.Name;

            var chapter = await dbContext.Chapters.Include(c => c.Novel).Include(c => c.Novel.Author)
                .FirstOrDefaultAsync(c => c.ChapterId == cid && c.NovelId == nid);
            var novel = chapter?.Novel;
            var author = novel?.Author;
            var isAuthor = author?.Username == username;

            if (chapter == null || novel == null || author == null ||
                (!chapter.Visibility || chapter.IsDeleted || novel.IsDeleted) && !isAuthor)
            {
                return NotFound(ApiResponse.ErrorResponse("找不到指定章节", 404));
            }

            var allChapters = await dbContext.Chapters
                .Where(c => c.NovelId == nid && !c.IsDeleted)
                .ToListAsync();

            var visibleChapters = isAuthor
                ? allChapters
                : allChapters.Where(c => c.Visibility).ToList();

            var ordered = visibleChapters
                .Where(c => c.Index > 0) // 过滤掉 index == 0 的简介
                .OrderBy(c => c.Index)
                .ToList();

            var currentIndex = ordered.FindIndex(c => c.ChapterId == cid);
            var prev = currentIndex > 0 ? ordered[currentIndex - 1] : null;
            var next = currentIndex >= 0 && currentIndex < ordered.Count - 1 ? ordered[currentIndex + 1] : null;

            var result = new
            {
                id = chapter.ChapterId,
                title = chapter.Title,
                content = chapter.Content,
                created_at = chapter.CreatedAt,
                updated_at = chapter.UpdatedAt,
                visibility = chapter.Visibility,
                draft = isAuthor ? new { title = chapter.DraftTitle, content = chapter.DraftContent } : null,
                prev = prev == null ? null : new { id = prev.ChapterId, title = prev.Title },
                next = next == null ? null : new { id = next.ChapterId, title = next.Title },
                novel = new
                {
                    id = novel.NovelId,
                    title = novel.Title,
                    author = new
                    {
                        id = novel.Author.UserId,
                        name = novel.Author.Username,
                        avatar = novel.Author.Avatar,
                        role = novel.Author.Role
                    },
                    cover = novel.Cover,
                    created_at = novel.CreatedAt,
                    updated_at = novel.UpdatedAt
                },
            };

            return Ok(ApiResponse.SuccessResponse(result));
        }

        private async Task<Models.Novel?> GetMyNovel(int id)
        {
            var username = User.Identity?.Name;
            if (string.IsNullOrEmpty(username)) return null;
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username && !u.IsDeleted);
            if (user == null) return null;
            var novel = await dbContext.Novels.Include(n => n.Author)
                .FirstOrDefaultAsync(n => n.NovelId == id);

            if (novel == null || novel.IsDeleted) return null;

            var isAuthor = novel.Author.Username == User.Identity?.Name;
            var isAdmin = user.Role == "admin" || user.Role == "mod";
            if (!isAuthor && !isAdmin) return null;
            return novel;
        }

        private async Task<Models.Chapter> GetMyChapter(int nid, int cid)
        {
            var username = User.Identity.Name;
            var chapter = await dbContext.Chapters.Include(c => c.Novel).Include(c => c.Novel.Author)
                .FirstOrDefaultAsync(c => c.NovelId == nid && c.ChapterId == cid);
            if (chapter?.Novel?.Author?.Username != username) return null;
            return chapter!;
        }

        /// <summary>
        /// 更新标题
        /// </summary>
        [HttpPut("{id}/title")]
        [Authorize]
        public async Task<IActionResult> UpdateNovelTitle(int id, [FromBody] NovelUpdateTitleDto dto)
        {
            var novel = await GetMyNovel(id);
            if (novel == null)
                return NotFound(ApiResponse.ErrorResponse("小说不存在或您没有编辑权限", 404));

            dbContext.Novels.Where(n => n.NovelId == id)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.Title, dto.Title)
                     .SetProperty(b => b.UpdatedAt, DateTime.UtcNow)
                );
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(novel).ReloadAsync();

            return await GetNovelById(id);
        }

        /// <summary>
        /// 更新简介
        /// </summary>
        [HttpPut("{id}/description")]
        [Authorize]
        public async Task<IActionResult> UpdateNovelDescription(int id, [FromBody] NovelUpdateDescriptionDto dto)
        {
            var novel = await GetMyNovel(id);
            if (novel == null)
                return NotFound(ApiResponse.ErrorResponse("小说不存在或您没有编辑权限", 404));

            dbContext.Novels.Where(c => c.NovelId == id)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.UpdatedAt, DateTime.UtcNow)
                );
            dbContext.Chapters.Where(c => c.NovelId == id && c.Index == 0)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.Content, dto.Description)
                );
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(novel).ReloadAsync();

            return await GetNovelById(id);
        }


        /// <summary>
        /// 更新封面图
        /// </summary>
        [HttpPut("{id}/cover")]
        [Authorize]
        [Consumes("image/png", "image/jpeg")]
        public async Task<IActionResult> UpdateNovelCover(int id)
        {
            var novel = await GetMyNovel(id);
            if (novel == null)
                return NotFound(ApiResponse.ErrorResponse("小说不存在或您没有编辑权限", 404));

            var imageBytes = await ImageUtils.ReadImageFromRequest(Request, 300, 425); // 1 : 1.414
            if (imageBytes == null) return BadRequest(ApiResponse.ErrorResponse("无效的文件类型", 400));

            var imageId = Guid.NewGuid();
            dbContext.Images.Add(new Models.Image
            {
                ImageId = imageId,
                Mime = "image/png",
                Content = imageBytes
            });
            await dbContext.SaveChangesAsync();

            dbContext.Novels.Where(c => c.NovelId == id)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.Cover, imageId)
                     .SetProperty(b => b.UpdatedAt, DateTime.UtcNow)
                );
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(novel).ReloadAsync();

            return await GetNovelById(id);
        }

        /// <summary>
        /// 更新标签
        /// </summary>
        [HttpPut("{id}/tags")]
        [Authorize]
        public async Task<IActionResult> UpdateNovelTags(int id, [FromBody] NovelTagsDto dto)
        {
            var novel = await GetMyNovel(id);
            if (novel == null)
                return NotFound(ApiResponse.ErrorResponse("小说不存在或您没有编辑权限", 404));

            if (dto.Tags.Length > 20 || dto.Tags.Any(t => t.Length == 0 || t.Length > 15))
            {
                return BadRequest(ApiResponse.ErrorResponse("标签数量或长度不正确", 400));
            }

            var oldTags = await dbContext.Tags.Where(t => t.NovelId == id).ToListAsync();
            var reuseTags = oldTags.Where(t => dto.Tags.Contains(t.TagName)).ToList();
            var excludeTags = oldTags.Where(t => !dto.Tags.Contains(t.TagName)).ToList();
            if (reuseTags.Count == dto.Tags.Length && excludeTags.Count == 0)
            {
                return await GetNovelById(id);
            }
            dbContext.Tags.RemoveRange(excludeTags);

            foreach (var tagName in dto.Tags)
            {
                if (reuseTags.Any(t => t.TagName == tagName)) continue;
                dbContext.Tags.Add(new Tag { NovelId = id, TagName = tagName });
            }
            dbContext.Novels.Where(c => c.NovelId == id)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.UpdatedAt, DateTime.UtcNow)
                );

            await dbContext.SaveChangesAsync();
            await dbContext.Entry(novel).ReloadAsync();

            return await GetNovelById(id);
        }

        /// <summary>
        /// 为小说添加一个新的空白章节
        /// </summary>
        /// <param name="id"></param>
        /// <example>1</example>
        [HttpPost("{id}/chapter/create")]
        [Authorize]
        public async Task<IActionResult> CreateChapterForNovel(int id, [FromBody] NovelChapterCreateDto dto)
        {
            var novel = await GetMyNovel(id);
            if (novel == null)
                return NotFound(ApiResponse.ErrorResponse("小说不存在或您没有编辑权限", 404));

            var nextIndex = await dbContext.Chapters
                .Where(c => c.NovelId == id)
                .MaxAsync(c => (int?)c.Index) ?? 0;

            var chapter = new Chapter
            {
                NovelId = id,
                Index = nextIndex + 1,
                Title = dto.Title,
                Content = "",
                DraftTitle = null,
                DraftContent = null,
                Visibility = false,
                IsDeleted = false,
                CreatedAt = null,
                UpdatedAt = null
            };

            dbContext.Chapters.Add(chapter);
            await dbContext.SaveChangesAsync();

            return await GetChapterById(id, chapter.ChapterId);
        }

        /// <summary>
        /// 更新章节内容
        /// </summary>
        [HttpPut("{nid}/chapter/{cid}")]
        [Authorize]
        public async Task<IActionResult> UpdateChapter(int nid, int cid, [FromBody] NovelChapterUpdateDto dto)
        {
            var chapter = await GetMyChapter(nid, cid);
            if (chapter == null) return NotFound(ApiResponse.ErrorResponse("章节不存在或您没有编辑权限", 404));
            if (dto.Visibility)
            {
                chapter.Visibility = true;
                chapter.Title = dto.Title;
                chapter.Content = dto.Content;
                var now = DateTime.Now;
                chapter.UpdatedAt = now;
                chapter.Novel.UpdatedAt = now;
                chapter.DraftTitle = null;
                chapter.DraftContent = null;
            }
            else
            {
                if (dto.Title != chapter.Title || dto.Content != chapter.Content)
                {
                    chapter.DraftTitle = dto.Title;
                    chapter.DraftContent = dto.Content;
                }
                else
                {
                    chapter.DraftTitle = null;
                    chapter.DraftContent = null;
                }
            }
            dbContext.Chapters.Update(chapter);
            dbContext.Novels.Update(chapter.Novel);
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(chapter).ReloadAsync();
            await dbContext.Entry(chapter.Novel).ReloadAsync();
            return await GetChapterById(nid, cid);
        }

        /// <summary>
        /// 更新章节可见性
        /// </summary>
        [HttpPut("{nid}/chapter/{cid}/visibility")]
        [Authorize]
        public async Task<IActionResult> UpdateChapterVisibility(int nid, int cid, [FromBody] NovelChapterVisibilityDto dto)
        {
            var chapter = await GetMyChapter(nid, cid);
            if (chapter == null) return NotFound(ApiResponse.ErrorResponse("章节不存在或您没有编辑权限", 404));
            chapter.Visibility = dto.Visibility;
            if (dto.Visibility)
            {
                var now = DateTime.Now;
                chapter.UpdatedAt = now;
                chapter.Novel.UpdatedAt = now;
            }
            dbContext.Chapters.Update(chapter);
            dbContext.Novels.Update(chapter.Novel);
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(chapter).ReloadAsync();
            await dbContext.Entry(chapter.Novel).ReloadAsync();
            return await GetChapterById(nid, cid);
        }

        /// <summary>
        /// 删除小说
        /// </summary>
        [HttpDelete("{id}")]
        [Authorize]
        public async Task<IActionResult> DeleteNovel(int id)
        {
            var novel = await GetMyNovel(id);
            if (novel == null)
            {
                return NotFound(ApiResponse.ErrorResponse("小说不存在或您没有编辑权限", 404));
            }
            novel.IsDeleted = true;
            await dbContext.SaveChangesAsync();
            return Ok(ApiResponse.SuccessResponse(true));
        }

        public class NovelCreateDto
        {
            public required string Title { get; set; }
            public required string Description { get; set; }

        }
        public class NovelUpdateTitleDto
        {
            public required string Title { get; set; }

        }
        public class NovelUpdateDescriptionDto
        {
            public required string Description { get; set; }

        }
        public class NovelTagsDto
        {
            public required string[] Tags { get; set; }
        }
        public class NovelChapterCreateDto
        {
            public required string Title { get; set; }
        }
        public class NovelChapterUpdateDto
        {
            public required bool Visibility { get; set; }
            public required string Title { get; set; }
            public required string Content { get; set; }
        }
        public class NovelChapterVisibilityDto
        {
            public required bool Visibility { get; set; }
        }
    }
}

